<?php

namespace App\Http\Controllers\API;

use App\Http\Requests\API\CreateDeviceAPIRequest;
use App\Http\Requests\API\UpdateDeviceAPIRequest;
use App\Models\Device;
use App\Repositories\DeviceRepository;
use App\Services\AliService;
use Illuminate\Http\Request;
use App\Http\Controllers\AppBaseController;
use InfyOm\Generator\Criteria\LimitOffsetCriteria;
use Prettus\Repository\Criteria\RequestCriteria;
use Response;

/**
 * Class DeviceController
 * @package App\Http\Controllers\API
 */
class DeviceAPIController extends AppBaseController
{
    /** @var  DeviceRepository */
    private $deviceRepository;
    private $server;


    public function __construct(Request $request)
    {
        $this->deviceRepository = app(DeviceRepository::class);
        $this->server = new AliService();
    }

    /**
     * @api {get} /api/devices 获取设备列表
     * @apiVersion 1.0.0
     * @apiDescription
     * @apiGroup Device
     *
     * @apiParam   {int} [page_limit=100] 每页显示的个数 默认为100.
     * @apiParam   {int} [page=1] 默认显示第一页
     * @apiParam   {string} [ProductKey]
     * @apiParam   {string} [DeviceName] 根据设备名字查找
     * @apiParam   {string} [desc] 降序的字段
     * @apiParam   {string} [asc] 升序的字段
     *
     * @apiHeader {String} Accept=application/json
     * @apiHeader {String} Authorization Bearer xxxxx
     *
     * @apiSampleRequest api/products
     * @apiSuccessExample {json} Success-Response:
     *     HTTP/1.1 200 OK
     * {
     * "code": 0,
     * "msg": "Products retrieved successfully",
     * "data": {
     * "current_page": 1,
     * "data": [
     * {
     * "id": 1,
     * "ProductKey": "VjkhzB7u4fE",
     * "ProductDesc": "Create Product",
     * "CatId": 10000,
     * "ProductName": "TestProduct",
     * "created_at": "2017-12-01 09:26:49",
     * "updated_at": "2017-12-01 09:26:49",
     * "deleted_at": null
     * }
     * ],
     * "first_page_url": "http://localhost:8000/api/products?page=1",
     * "from": 1,
     * "last_page": 1,
     * "last_page_url": "http://localhost:8000/api/products?page=1",
     * "next_page_url": null,
     * "path": "http://localhost:8000/api/products",
     * "per_page": 100,
     * "prev_page_url": null,
     * "to": 1,
     * "total": 1
     * }
     * }
     **/
    public function index(Request $request)
    {
        $this->deviceRepository->pushCriteria(new RequestCriteria($request));
        $this->deviceRepository->pushCriteria(new LimitOffsetCriteria($request));


        $page_limit = empty($request->input('page_limit')) ? 100 : $request->input('page_limit');
//        $ProductKey = $request->input('ProductKey');
//        if (empty($ProductKey)) {
//            return $this->fail(-1, 'ProductKey为空');
//        }

        $devices = $this->deviceRepository->getDeviceByProduct($page_limit, $request->input());

        return $this->success($devices->toArray(), 'Devices retrieved successfully');
    }

    /**
     * @api {post} api/devices  注册设备
     * @apiVersion 1.0.0
     * @apiName DeviceStore
     * @apiGroup Device
     *
     * @apiParam   {string} ProductKey 产品id
     * @apiParam   {string} DeviceName 设备名称
     *
     * @apiSuccessExample {json} Success-Response:
     *     HTTP/1.1 200 OK
     *   {
     * "RequestId":"120F5EB3-7023-4F0C-B419-9303AB336885",
     * "Success":true
     * "DeviceId":"", //阿里云颁发的设备id 全局唯一
     * "DeviceName":"",//设备名称，用户自定义或系统生成
     * "DeviceSecret":"",//设备私钥
     * "DeviceStatus":"",//预留状态字段
     * "ErrorMessage":""//错误信息
     * }
     */
    public function store(CreateDeviceAPIRequest $request)
    {
        $input = $request->all();
        $rules = array("ProductKey" => "required",
            "DeviceName" => "required",
        );
        $messages = array("ProductKey.required" => "ProductKey为空",
            "DeviceName.required" => "设备名称");
        $result = $this->validate($input, $rules, $messages);
        if ($result["code"] != 0) {
            return $this->fail(self::VALIDATE_ERROR, $result["errors"]);
        }

        $res = $this->server->deviceRegister($input['ProductKey'], $input['DeviceName']);
        if ($res->Success) {
            $input['DeviceId'] = $res->DeviceId;
            $input['DeviceId'] = $res->DeviceId;
            $input['DeviceSecret'] = $res->DeviceSecret;

            $devices = $this->deviceRepository->create($input);
            return $this->success($devices->toArray(), 'Device saved successfully');
        } else {
            return $this->fail(-1, $res->ErrorMessage);
        }
    }

    /**
     * @api {get} api/devices/:id  查询设备信息，设备状态，设备影子
     * @apiVersion 1.0.0
     * @apiName show
     * @apiGroup Device

     * * @apiSuccessExample {json} Success-Response:
     *     HTTP/1.1 200 OK
     * {
     * "code": 0,
     * "msg": "Device retrieved successfully",
     * "data": {
     * "device": {
     * "id": 3,
     * "DeviceId": "vvUgwAX2I4gkzSspFWCe",
     * "DeviceName": "device01",
     * "DeviceSecret": "JQL9JgSEr4pHMSszSvuzwWAjhpXgr7EA",
     * "ProductKey": "Sdv5hMAlAFx",
     * "Props": null,
     * "created_at": "2017-12-05 16:21:51",
     * "updated_at": "2017-12-05 16:21:51",
     * "deleted_at": null
     * },
     * "status": {
     * "Status": "OFFLINE",
     * "DeviceId": "vvUgwAX2I4gkzSspFWCe",
     * "DeviceName": "device01",
     * "LastOnlineTime": "2017-12-06 15:15:57"
     * },
     * "shadow": "{\"state\":{\"reported\":{\"light\":\"high\",\"temperature\":28,\"led\":\"on\",\"window\":\"open\",\"app\":\"56\",\"cmd\":\"on\",\"group\":1}},\"metadata\":{\"reported\":{\"light\":{\"timestamp\":1512544558},\"temperature\":{\"timestamp\":1512544558},\"led\":{\"timestamp\":1512544558},\"window\":{\"timestamp\":1512544558},\"app\":{\"timestamp\":1512470396},\"cmd\":{\"timestamp\":1512470396},\"group\":{\"timestamp\":1512470396}}},\"timestamp\":1512544558,\"version\":98}"
     * }
     * }
     */
    public function show($id)
    {
        /** @var Device $device */
        $device = $this->deviceRepository->findWithoutFail($id);

        if (empty($device)) {
            return $this->fail(-1, 'Device not found');
        }
        //查询设备状态
        $status = $this->server->getDeviceStatus($device['ProductKey'], [$device['DeviceName']]);
        if ($status->Success) {
            $statusInfo = $status->DeviceStatusList->DeviceStatus[0];
        } else {
            return $this->fail(-1, $status->ErrorMessage);

        }
        //查询设备影子
        $shadow = $this->server->getDeviceShadow($device['ProductKey'], $device['DeviceName']);

        if ($shadow->Success) {
            $shadowInfo = empty($shadow->ShadowMessage) ? null : $shadow->ShadowMessage;
        } else {
            return $this->fail(-1, $shadow->ErrorMessage);
        }
        return $this->success(['device' => $device->toArray(), 'status' => $statusInfo, 'shadow' => $shadowInfo], 'Device retrieved successfully');
    }

    /**
     * @api {put} api/devices/:id  修改设备，这里只可以修改设备属性
     * @apiVersion 1.0.0
     * @apiName update
     * @apiGroup Device
     * @apiParam   {string} DeviceName 设备名称
     * @apiParam   {string} Props 属性json string
     * * @apiSuccessExample {json} Success-Response:
     *     HTTP/1.1 200 OK
     * {
     * "code": 0,
     * "msg": "ok",
     * "data": {
     * "id": 1,
     * "ProductKey": "Sdv5hMAlAFx",
     * "ProductDesc": "CCDD",
     * "CatId": 10000,
     * "ProductName": "继电器",
     * "created_at": "2017-12-04 18:10:44",
     * "updated_at": "2017-12-06 17:15:22",
     * "deleted_at": null
     * }
     * }
     */
    public function update($id, UpdateDeviceAPIRequest $request)
    {
        $input = $request->all();

        $rules = array(
            "DeviceName" => "required",
            "Props" => "required"
        );
        $messages = array(
            "DeviceName.required" => "设备名称为空",
            "Props.required" => "属性描述不能为空");
        $result = $this->validate($input, $rules, $messages);
        if ($result["code"] != 0) {
            return $this->fail(self::VALIDATE_ERROR, $result["errors"]);
        }

        /** @var Device $device */
        $device = $this->deviceRepository->findWithoutFail($id);

        if (empty($device)) {
            return $this->fail(-1, 'Device not found');
        }

        $input['ProductKey'] = $device['ProductKey'];

        $device = $this->deviceRepository->update($input, $id);

        return $this->success($device->toArray(), 'Device updated successfully');
    }

    /**
     * @api {delete} api/devices/:id  删除产品
     * @apiVersion 1.0.0
     * @apiName store
     * @apiGroup Device
     * * @apiSuccessExample {json} Success-Response:
     *     HTTP/1.1 200 OK
     * {
     * "code": 0,
     * "msg": "ok",
     * "data": {
     * }
     */
    public function destroy($id)
    {
        /** @var Device $device */
        $device = $this->deviceRepository->findWithoutFail($id);

        if (empty($device)) {
            return $this->fail(-1, 'Device not found');
        }

        $device->delete();

        return $this->success($id, 'Device deleted successfully');
    }

    /**
     * @api {post} api/devices/:id/sendToTopic  发布消息到topic
     * @apiVersion 1.0.0
     * @apiName sendToTopic
     * @apiGroup Device
     *
     * @apiParam   {string} TopicFullName 消息发送目的Topic名字，如/productKey/deviceName/get
     * @apiParam   {string} MessageContent 发送的消息，将消息内容二进制进行Base64编码后得到的字符串
     * @apiParam   {int} [Qos =0] 指定消息发送的方式，默认为0 0：最多发送一次，1：最少发送一次
     * 需要注意的是：消息在IoT套件中最多保存7天
     *
     * @apiSuccessExample {json} Success-Response:
     *     HTTP/1.1 200 OK
     * {
     * "RequestId":"BB71E443-4447-4024-A000-EDE09922891E",
     * "Success":true,
     * "MessageId":889455942124347329
     * }
     */
    public function sendToTopic(Request $request, $id)
    {
        $input = $request->all();
        //校验
        $rules = array(
            "TopicFullName" => "required",
            "MessageContent" => "required",
        );
        $messages = array(
            "TopicFullName.required" => "topic为空",
            "MessageContent.required" => "内容为空");
        $result = $this->validate($input, $rules, $messages);
        if ($result["code"] != 0) {
            return $this->fail(self::VALIDATE_ERROR, $result["errors"]);
        }

        $input['Qos'] = empty($input['Qos']) ? 0 : $input['Qos'];


        $device = $this->deviceRepository->findWithoutFail($id);

        if (empty($device)) {
            return $this->fail(-1, 'Device not found');
        }

        $res = $this->server->publishToTopic($device['ProductKey'], $input['TopicFullName'], base64_encode($input['MessageContent']), $input['Qos']);
        if ($res->Success) {
            return $this->success($res);
        } else {
            return $this->fail(-1, $res->ErrorMessage);
        }

    }

    /**
     * @api {post} api/devices/:id/sendToDevice  发消息给设备并同步返回响应
     * @apiVersion 1.0.0
     * @apiName sendToDevice
     * @apiGroup Device
     *
     * @apiParam   {string} DeviceName 设备名称
     * @apiParam   {string} RequestBase64Byte 请求消息内容，需要是经过Base64编码得到的字符串数据
     * @apiParam   {int} [Timeout] 表示等待设备回复消息的时间，单位是毫秒，允许范围是1000~5000
     *
     * @apiSuccessExample {json} Success-Response:
     *     HTTP/1.1 200 OK
     * {
     * "RequestId":"41C4265E-F05D-4E2E-AB09-E031F501AF7F",
     * "Success":true,
     * "RrpcCode":"SUCCESS",
     * "PayloadBase64Byte":"d29ybGQgaGVsbG8="
     * "MessageId":889455942124347392
     * }
     */
    public function sendToDevice(Request $request, $id)
    {
        $input = $request->all();
        //校验
        $rules = array(
            "DeviceName" => "required",
            "RequestBase64Byte" => "required",
        );
        $messages = array(
            "DeviceName.required" => "device为空",
            "RequestBase64Byte.required" => "消息内容为空",);
        $result = $this->validate($input, $rules, $messages);
        if ($result["code"] != 0) {
            return $this->fail(self::VALIDATE_ERROR, $result["errors"]);
        }

        $input['Timeout'] = empty($input['Timeout']) ? 1000 : $input['Timeout'];

        $device = $this->deviceRepository->findWithoutFail($id);

        if (empty($device)) {
            return $this->fail(-1, 'Device not found');
        }
//        dd(base64_encode($input['RequestBase64Byte']));
        $res = $this->server->sendMessageToDevice($device['ProductKey'], $input['DeviceName'], base64_encode($input['RequestBase64Byte']), $input['Timeout']);

        if ($res->Success) {
            return $this->success($res);
        } else {
            return $this->fail(-1, $res->ErrorMessage);
        }
    }

    /**
     * @api {get} api/devices/:id/shadow  只查询设备影子
     * @apiVersion 1.0.0
     * @apiName sendDeviceShadow
     * @apiGroup Device
     * * @apiSuccessExample {json} Success-Response:
     *     HTTP/1.1 200 OK
     * {
     * "code": 0,
     * "msg": "Device retrieved successfully",
     * "data": {
     * "{\"state\":{\"reported\":{\"light\":\"high\",\"temperature\":28,\"led\":\"on\",\"window\":\"open\",\"app\":\"56\",\"cmd\":\"on\",\"group\":1}},\"metadata\":{\"reported\":{\"light\":{\"timestamp\":1512544558},\"temperature\":{\"timestamp\":1512544558},\"led\":{\"timestamp\":1512544558},\"window\":{\"timestamp\":1512544558},\"app\":{\"timestamp\":1512470396},\"cmd\":{\"timestamp\":1512470396},\"group\":{\"timestamp\":1512470396}}},\"timestamp\":1512544558,\"version\":98}"
     * }
     * }
     */
    public function sendDeviceShadow(Request $request, $id){
        $device = $this->deviceRepository->findWithoutFail($id);

        if (empty($device)) {
            return $this->fail(-1, 'Device not found');
        }
        //查询设备影子
        $shadow = $this->server->getDeviceShadow($device['ProductKey'], $device['DeviceName']);

        if ($shadow->Success) {
            $shadowInfo = empty($shadow->ShadowMessage) ? null : $shadow->ShadowMessage;
            return $this->success($shadowInfo, 'Device retrieved successfully');

        } else {
            return $this->fail(-1, $shadow->ErrorMessage);
        }
    }
}
